/*  
  -- The Lime II Project -- 

  A tuplespaces-based middleware for coordinating agents and mobile hosts.
  Copyright (C) 2005.
  Gian Pietro Picco, Amy L. Murphy, Lorenzo Bellini.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.

  You should have received this copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
*/

package lime2;
import java.util.*;

/**
 * Caches incoming remote ops to protect against duplicates. Duplicates are critical in the case of PASSIVE_OPEN 
 * requests since each of them would be assigned a thread of the pool.
 * 
 * @author Gian Pietro Picco
 * @author Amy Murphy
 * @author Lorenzo Bellini
 */

class DupCache 
{
 private static Vector cacheV;	  // allows aging of incoming remote ops
 private static Hashtable cacheH; // allows efficient retrieval of remote ops (stores position within cacheV) 
 private static int size;	      // number of cached remote ops
 
 // static initializer
 static 
 { 
  if (LimeConstants.CACHE_DUPS_ENABLED) 
  {
   cacheV = new Vector();	
   cacheH = new Hashtable(); 
   size = 0; 
  }	
 } 

 /**
  * Returns true if the given op is a duplicate of an op in the cache; as a side-effect the given op is cached.
  * <br>
  * This method is synchronized since it can be invoked by the Poller (within CommunicationMgr) and the Defragger 
  * (within FragmentationProxy): we must preserve consistency of the cache.
  * 
  * @param ro given op
  * @return <code>true</code> if given op is a duplicate, <code>false</code> otherwise 
  */
 synchronized static boolean isDuplicate(RemoteOp ro)
 {
  if (!LimeConstants.CACHE_DUPS_ENABLED) return false;
   
  boolean ret = false;	
  Integer nn = (Integer) cacheH.get(ro); 	
  
  if (nn != null)
  {
   cacheV.remove(nn.intValue());
   cacheV.addElement(ro);
   cacheH.put(ro, new Integer(size - 1)); // there is at least an op in the cache !
   ret = true;
  }	
  else
  {
   if (size > LimeConstants.CACHE_DUPS_SIZE)
   {
    RemoteOp tmp = (RemoteOp) cacheV.remove(0);
    cacheH.remove(tmp);
    size--;
   }	
   size++;
   cacheV.addElement(ro);	
   cacheH.put(ro, new Integer(size - 1));	
  }
  
  return ret;
 }	
  
 /**
  * Refreshes the cache.
  */
 synchronized static void clean()
 {
  if (LimeConstants.CACHE_DUPS_ENABLED)
  {
   cacheV.clear();
   cacheH.clear();
   size = 0;
  }	
 }
 
}
